/*              Copyright(c) 2008 Dave Sexton              *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace DaveSexton.Sandcastle
{
	public sealed partial class UrlMappingProviderDialog : Form
	{
		#region Public Properties
		public ICollection<KeyValuePair<Type, string>> SelectedProviderTypes
		{
			get
			{
				List<KeyValuePair<Type, string>> types = new List<KeyValuePair<Type, string>>(selectedTypes.Rows.Count);

				foreach (DataRow row in selectedTypes.Rows)
				{
					if (row.RowState != DataRowState.Deleted && row.RowState != DataRowState.Detached)
					{
						if ((Type) row["Type"] == typeof(XmlUrlMappingProvider))
							types.Add(new KeyValuePair<Type, string>(null, null));
						else
							types.Add(new KeyValuePair<Type, string>(
								(Type) row["Type"], 
								(row.IsNull("AssemblyPath")) ? null : (string) row["AssemblyPath"]));
					}
				}

				return types.AsReadOnly();
			}
		}
		#endregion

		#region Private / Protected
		private MessageBoxOptions MessageBoxOptions
		{
			get
			{
				if (RightToLeft == RightToLeft.Yes)
					return MessageBoxOptions.RightAlign | MessageBoxOptions.RtlReading;
				else
					return (MessageBoxOptions) 0;
			}
		}

		private readonly DataTable availableTypes;
		private readonly DataTable selectedTypes;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="UrlMappingProviderDialog" /> class.
		/// </summary>
		public UrlMappingProviderDialog()
		{
			InitializeComponent();

			availableDataGridView.AutoGenerateColumns = false;
			selectedDataGridView.AutoGenerateColumns = false;

			availableTypes = new DataTable();
			availableTypes.Locale = System.Globalization.CultureInfo.CurrentCulture;

			DataColumn typeColumn = availableTypes.Columns.Add("Type", typeof(Type));
			availableTypes.Columns.Add("Name", typeof(string));
			availableTypes.Columns.Add("FullName", typeof(string));
			availableTypes.Columns.Add("Assembly", typeof(Assembly));
			availableTypes.Columns.Add("AssemblyPath", typeof(string));

			selectedTypes = availableTypes.Clone();
			selectedTypes.RowChanged += new DataRowChangeEventHandler(selectedTypes_RowChanged);
			selectedTypes.RowDeleted += new DataRowChangeEventHandler(selectedTypes_RowDeleted);

			// update the availableTypes schema where it must differ from the selectedTypes schema
			typeColumn.Unique = true;
			availableTypes.PrimaryKey = new DataColumn[] { typeColumn };

			availableDataGridView.DataSource = availableTypes;
			selectedDataGridView.DataSource = selectedTypes;
		}
		#endregion

		#region Methods
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1817:DoNotCallPropertiesThatCloneValuesInLoops")]
		private static void SetRowDescriptions(DataGridView grid, int start, int end)
		{
			for (int i = start; i < end; i++)
			{
				DataGridViewRow row = grid.Rows[i];

				DataRow data = ((DataRowView) row.DataBoundItem).Row;
				Type type = (Type) data["Type"];

				string description = ComponentDescriptor.GetDescription(type);

				if (!string.IsNullOrEmpty(description))
				{
					foreach (DataGridViewCell cell in row.Cells)
						cell.ToolTipText = description;
				}
			}
		}

		private void LoadProvidersInAssembly(string file)
		{
			LoadProvidersInAssembly(Assembly.LoadFrom(file), file);
		}

		private void LoadProvidersInAssembly(Assembly assembly, string file)
		{
			availableTypes.BeginInit();

			try
			{
				foreach (Type type in assembly.GetTypes())
				{
					if (type.IsSubclassOf(typeof(UrlMappingProvider)) && type != typeof(FileUrlMappingProvider) && availableTypes.Rows.Find(type) == null)
						availableTypes.Rows.Add(type, ComponentDescriptor.GetDisplayName(type), type.FullName, type.Assembly, file);
				}
			}
			finally
			{
				availableTypes.EndInit();
			}
		}

		private void SelectType(DataGridViewRow row)
		{
			DataRow data = ((DataRowView) row.DataBoundItem).Row;

			// NOTE: allow the same type to be added multiple times
			selectedTypes.Rows.Add(data.ItemArray);
		}

		private void UnselectType(DataGridViewRow row)
		{
			selectedTypes.Rows.RemoveAt(row.Index);
		}
		#endregion

		#region Event Handlers
		protected override void OnLoad(EventArgs e)
		{
			LoadProvidersInAssembly(Assembly.GetExecutingAssembly(), null);

			base.OnLoad(e);
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
		private void browseButton_Click(object sender, EventArgs e)
		{
			if (assembliesOpenFileDialog.ShowDialog(this) == DialogResult.OK)
			{
				foreach (string file in assembliesOpenFileDialog.FileNames)
				{
					if (!string.IsNullOrEmpty(file))
					{
						try
						{
							LoadProvidersInAssembly(file);
						}
						catch (Exception ex)
						{
							MessageBox.Show(this,
								string.Format(System.Globalization.CultureInfo.CurrentCulture,
								Resources.Errors.CannotLoadAssembly, file, Environment.NewLine, ex.Message),
								Resources.Errors.CannotLoadAssemblyCaption, MessageBoxButtons.OK, MessageBoxIcon.Error,
								MessageBoxDefaultButton.Button1, MessageBoxOptions);
						}
					}
				}
			}
		}

		private void availableDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
		{
			if (e.RowIndex > -1)
			{
				SelectType(availableDataGridView.Rows[e.RowIndex]);
			}
		}

		private void availableContextMenuStrip_Opening(object sender, CancelEventArgs e)
		{
			selectToolStripMenuItem.Enabled = availableDataGridView.SelectedRows.Count > 0;
		}

		private void selectToolStripMenuItem_Click(object sender, EventArgs e)
		{
			foreach (DataGridViewRow row in availableDataGridView.SelectedRows)
			{
				SelectType(row);
			}
		}

		private void selectedContextMenuStrip_Opening(object sender, CancelEventArgs e)
		{
			removeToolStripMenuItem.Enabled = selectedDataGridView.SelectedRows.Count > 0;
		}

		private void removeToolStripMenuItem_Click(object sender, EventArgs e)
		{
			foreach (DataGridViewRow row in selectedDataGridView.SelectedRows)
			{
				UnselectType(row);
			}
		}

		private void availableDataGridView_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
		{
			SetRowDescriptions(availableDataGridView, e.RowIndex, availableDataGridView.Rows.Count);
		}

		private void selectedDataGridView_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
		{
			SetRowDescriptions(selectedDataGridView, e.RowIndex, selectedDataGridView.Rows.Count);
		}

		private void selectedTypes_RowDeleted(object sender, DataRowChangeEventArgs e)
		{
			okButton.Enabled = selectedTypes.Rows.Count > 0;
		}

		private void selectedTypes_RowChanged(object sender, DataRowChangeEventArgs e)
		{
			okButton.Enabled = selectedTypes.Rows.Count > 0;
		}
		#endregion
	}
}